//boost headers
#include <boost/optional.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>

//project headers
#include "Validator/Validator.h"
#include "Server/Server.h"
#include "SingletonHolder.h"
#include "Options.h"
#include "DataContainer.h"
#include "Worker.h"
#include "Alive.h"

using namespace std;


int main(void)
{
	SingletonHolder::Instance("mvstupny").WriteMsg("Starting........");
	try
	{
		Options options;

		Validator::Validator aValid(options.GetData("validator_directory"));
		aValid.Init();

		boost::optional<Validator::Scheme> selectedScheme = aValid.GetScheme(options.GetData("validator_sch_name"));
		

		if(selectedScheme.is_initialized())
		{
			Validator::Scheme validScheme = selectedScheme.get();
			size_t thread_num = boost::lexical_cast<size_t>(options.GetData("server_threads"));
			Server server(options.GetData("server_port"),thread_num);
			boost::thread th(boost::bind(&Server::Run,&server));
			
			SingletonHolder::Instance("mvstupny").WriteMsg("----------------------Up & Running------------------");

			while(1)
			{
				boost::optional<boost::shared_ptr<ConnectionContainer> > aContainer = server.GetReceived();
				if(aContainer.is_initialized())
				{
					boost::shared_ptr<ConnectionContainer> aReceivedContainer  = aContainer.get();

					if(aReceivedContainer->data.GetCommand() != 'a')		//ak dosli data ne dotaz nato ci zijeme alebo ne
					{
						Worker work(aReceivedContainer->data,validScheme,options.GetData("client_address"),options.GetData("client_port"),options.GetData("store_directory"));

						boost::thread work_th(work); //spustime pracu v vlastnom vlakne
					}
					else	//dosiel dotaz nato ci zijeme
					{
						Alive alive(aReceivedContainer->clientAddress,aReceivedContainer->port);
						//alive();
						boost::thread th_alv(alive);
					}
				}
			}

			server.Stop();
			th.join();

		}
		else
		{
			SingletonHolder::Instance().WriteEx("Cant load validation scheme!");
			return -1;
		}

		return 0;
	}
	catch(exception &ex)
	{
		SingletonHolder::Instance().WriteEx(ex.what());
	}
}
